﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace Blank.CommonLib.Utils
{
    public static class XmlUtil
    {
        public static event XmlAttributeEventHandler UnknownAttribute;
        public static event XmlElementEventHandler UnknownElement;
        public static event XmlNodeEventHandler UnknownNode;
        public static event UnreferencedObjectEventHandler UnreferencedObject;

        /// <summary>
        /// 反序列化XML
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static T Deserialize<T>(this string xmlString)
        {
            return Deserialize<T>(LoadType.String, xmlString);
        }
        /// <summary>
        /// 反序列化XML
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <returns></returns>
        public static T Deserialize<T>(LoadType loadType, string parameter)
        {
            XmlDocument xdoc = new XmlDocument();
            switch (loadType)
            {
                case LoadType.String:
                    xdoc.LoadXml(parameter);
                    break;
                case LoadType.FilePath:
                    xdoc.Load(parameter);
                    break;
                default:
                    throw new Exception("Unknown loadType");
            }
            using (XmlNodeReader reader = new XmlNodeReader(xdoc.DocumentElement))
            {
                XmlSerializer ser = new XmlSerializer(typeof(T));
                ser.UnknownAttribute += UnknownAttribute;
                ser.UnknownElement += UnknownElement;
                ser.UnknownNode += UnknownNode;
                ser.UnreferencedObject += UnreferencedObject;
                object obj = ser.Deserialize(reader);
                return (T)obj;
            }

        }
        /// <summary>
        /// 序列化XML
        /// </summary>
        /// <param name="obj">被序列化的对象</param>
        /// <param name="path">要存放的文件名（包括路径）</param>
        public static void Serialize(this object obj, string path)
        {
            if (File.Exists(path))
                File.Delete(path);
            XmlSerializer ser = new XmlSerializer(obj.GetType());
            ser.UnknownAttribute += UnknownAttribute;
            ser.UnknownElement += UnknownElement;
            ser.UnknownNode += UnknownNode;
            ser.UnreferencedObject += UnreferencedObject;
            using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
            {
                ser.Serialize(fs, obj);
            }
        }
        /// <summary>
        /// 序列化XML
        /// </summary>
        /// <param name="obj">被序列化的对象</param>
        /// <returns></returns>
        public static string Serialize(this object obj)
        {
            XmlSerializer ser = new XmlSerializer(obj.GetType());
            ser.UnknownAttribute += UnknownAttribute;
            ser.UnknownElement += UnknownElement;
            ser.UnknownNode += UnknownNode;
            ser.UnreferencedObject += UnreferencedObject;
            using (MemoryStream ms = new MemoryStream())
            {
                using (XmlTextWriter xw = new XmlTextWriter(ms, Encoding.UTF8))
                {
                    //Create our own namespaces for the output
                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    //Add an empty namespace and empty value
                    ns.Add("", "");
                    ser.Serialize(xw, obj, ns);
                    ms.Position = 0;
                    XmlDocument doc = new XmlDocument();
                    doc.Load(ms);
                    return doc.OuterXml;
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T Serialize<T>(this object obj, ReturnType returnType)
            where T : class
        {
            XmlSerializer ser = new XmlSerializer(obj.GetType());
            ser.UnknownAttribute += UnknownAttribute;
            ser.UnknownElement += UnknownElement;
            ser.UnknownNode += UnknownNode;
            ser.UnreferencedObject += UnreferencedObject;
            using (MemoryStream ms = new MemoryStream())
            {
                using (XmlTextWriter xw = new XmlTextWriter(ms, Encoding.UTF8))
                {
                    //Create our own namespaces for the output
                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    //Add an empty namespace and empty value
                    ns.Add("", "");
                    ser.Serialize(xw, obj, ns);
                    ms.Position = 0;
                    XmlDocument doc = new XmlDocument();
                    doc.Load(ms);

                    if (returnType == ReturnType.String)
                        return obj.Serialize() as T;
                    else if (returnType == ReturnType.XmlDocument)
                    {
                        return doc as T;
                    }
                    else if (returnType == ReturnType.XmlElement)
                    {
                        return doc.DocumentElement as T;
                    }
                    return default(T);
                }
            }
        }
    }
    /// <summary>
    /// 加载XML的方式
    /// </summary>
    public enum LoadType
    {
        /// <summary>
        /// 传入的为XML字符串
        /// </summary>
        String,
        /// <summary>
        /// 传入的为XML文件所在路径
        /// </summary>
        FilePath
    }

    public enum ReturnType
    {
        String,
        XmlDocument,
        XmlElement
    }
}
